package com.gitee.chili.leisure.util;

import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalField;
import java.time.temporal.TemporalUnit;
import java.util.Date;

public class DateUtil {

    /**
     * 线程安全的方式
     */
    private static final DateTimeFormatter DEFAULT_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    private static final DateTimeFormatter YMD_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd");

    private static final ZoneId SYSTEM_DEFAULT = ZoneId.systemDefault();

    private static final Integer FIRST_SECOND = 0;

    private static final Integer LAST_HOURS = 23;

    private static final Integer LAST_SECOND = 59;

    /**
     * Date to string
     */
    public static String convert(Date date) {
        return convert(date, DEFAULT_FORMAT);
    }

    public static String convert(Date date, DateTimeFormatter dateTimeFormatter) {
        return LocalDateTime.ofInstant(date.toInstant(), SYSTEM_DEFAULT).format(dateTimeFormatter);
    }

    /**
     * string to date
     */
    public static Date convert(String date) {
        return convert(date, DEFAULT_FORMAT);
    }

    public static Date convert(String date, DateTimeFormatter dateTimeFormatter) {
        return asDate(LocalDateTime.from(dateTimeFormatter.parse(date)));
    }

    /**
     * 指定时间的 {@code yyyy-MM-dd} 字符串类型
     */
    public static String getDateStr(Date date) {
        return YMD_FORMAT.format(LocalDateTime.ofInstant(date.toInstant(), SYSTEM_DEFAULT));
    }

    public static String getDateStr() {
        return YMD_FORMAT.format(LocalDate.now(SYSTEM_DEFAULT));
    }

    /**
     * 计算量时间的差
     * <code>
     * long days = duration.toDays(); 相差的天数
     * long hours = duration.toHours(); 相差的小时数
     * long minutes = duration.toMinutes(); 相差的分钟数
     * long millis = duration.toMillis(); 相差毫秒数
     * long nanos = duration.toNanos(); 相差的纳秒数
     * </code>
     *
     * @see Duration
     */
    public static Duration diffTime(Date first, Date second) {
        LocalDateTime firstTime = LocalDateTime.ofInstant(first.toInstant(), SYSTEM_DEFAULT);
        LocalDateTime secondTime = LocalDateTime.ofInstant(second.toInstant(), SYSTEM_DEFAULT);
        return Duration.between(firstTime, secondTime);
    }

    public static LocalDateTime current() {
        return LocalDateTime.now(SYSTEM_DEFAULT);
    }

    public static long timestamp() {
        return System.currentTimeMillis();
    }

    public static String valueOfTimestamp() {
        return String.valueOf(System.currentTimeMillis());
    }

    /**
     * 获取当前时间
     */
    public static Date now() {
        return asDate(current());
    }

    /**
     * LocalDateTime to Date
     */
    public static Date asDate(LocalDateTime time){
        return Date.from(time.atZone(SYSTEM_DEFAULT).toInstant());
    }

    /**
     * 在当前时间的基础上进行减法预算
     *
     * @param amount 减去的时间
     * @param unit   减去时间的类型
     * @see ChronoUnit 引用对应的类型
     */
    public static Date minus(int amount, TemporalUnit unit) {
        return asDate(current().minus(amount, unit));
    }

    /**
     * 在当前时间的基础上进行加法预算
     *
     * @param amount 加去的时间
     * @param unit   加去时间的类型
     * @see ChronoUnit 引用对应的类型
     */
    public static Date plus(int amount, TemporalUnit unit) {
        return asDate(current().plus(amount, unit));
    }

    /**
     * 获取指定类型的日期部分
     *
     * @param date  想从中获取日期部分的时间
     * @param field 类型
     * @see ChronoField 引用类型
     */
    public static Integer getDatePortion(Date date, TemporalField field) {
        return LocalDateTime.ofInstant(date.toInstant(), SYSTEM_DEFAULT).get(field);
    }

    /**
     * 获取当前时间指定类型的日期部分
     *
     * @param field 类型
     * @see ChronoField 引用类型
     */
    public static Integer getDatePortion(TemporalField field) {
        return getDatePortion(now(), field);
    }

    /**
     * 减去指定的天数并且其他时间归零
     *
     * @param date   时间
     * @param amount 天数
     */
    public static Date subtractDaysAndZeroOthers(Date date, int amount) {
        LocalDateTime time = LocalDateTime.ofInstant(date.toInstant(), SYSTEM_DEFAULT).minusDays(amount);
        return ofFirstTime(time);
    }

    /**
     * 获取昨天的第一秒的日期
     */
    public static Date getDateOfYesterdaysFirstSecond() {
        return subtractDaysAndZeroOthers(now(), 1);
    }

    /**
     * 获取昨天最后一秒的日期
     */
    public static Date getDateOfYesterdaysLastSecond() {
        return ofLastTime(current().minus(1, ChronoUnit.DAYS));
    }

    /**
     * 当前月的第一天
     */
    public static Date getDateOfFirstDaysOfMonth() {
        return ofFirstTime(current().withDayOfMonth(1));
    }

    /**
     * 获取今天第一秒的时间
     */
    public static Date getDateOfTodayFirstSecond() {
        return ofFirstTime(current());
    }

    /**
     * 获取今天最后一秒的时间
     */
    public static Date getDateOfTodayLastSecond() {
        return ofLastTime(current());
    }

    /**
     * 获取指定时间 第一秒的日期
     */
    public static Date ofFirstTime(LocalDateTime time) {
        return setLocalDateTime(time, time.getYear(), time.getMonthValue(), time.getDayOfMonth(),
                FIRST_SECOND, FIRST_SECOND, FIRST_SECOND);
    }

    /**
     * 获取指定时间 最后一秒的日期
     */
    public static Date ofLastTime(LocalDateTime time) {
        return setLocalDateTime(time, time.getYear(), time.getMonthValue(), time.getDayOfMonth(),
                LAST_HOURS, LAST_SECOND, LAST_SECOND);
    }

    private static Date setLocalDateTime(LocalDateTime dateTime, int year, int month, int days,
                                         int hours, int minute, int second) {
        return asDate(dateTime.withYear(year).withMonth(month).withDayOfMonth(days)
                .withHour(hours).withMinute(minute).withSecond(second).withNano(FIRST_SECOND));
    }

    public static void main(String[] args) {
        System.out.println(convert(getDateOfTodayLastSecond()));
    }
}
